package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.Constant;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.dto.NoteFormDTO;
import com.tianji.learning.domain.po.Note;
import com.tianji.learning.domain.query.NoteAdminPageQuery;
import com.tianji.learning.domain.query.NotePageQuery;
import com.tianji.learning.domain.vo.NoteAdminDetailVO;
import com.tianji.learning.domain.vo.NoteAdminVO;
import com.tianji.learning.domain.vo.NoteVO;
import com.tianji.learning.mapper.NoteMapper;
import com.tianji.learning.service.INoteService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import net.bytebuddy.asm.Advice;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 笔记表 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2025-04-05
 */
@Service
@RequiredArgsConstructor
public class NoteServiceImpl extends ServiceImpl<NoteMapper, Note> implements INoteService {

    private final RabbitMqHelper mqHelper;
    private final UserClient userClient;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final CategoryCache categoryCache;

    @Override
    public void hiddenNote(Long id, Boolean hidden) {
        Note note = new Note();
        note.setId(id);
        note.setHidden(hidden);
        updateById(note);
    }

    @Override
    public NoteAdminDetailVO queryNoteDetail(Long id) {
        Note note = getById(id);
        AssertUtils.isNotNull(note, "笔记不存在");

        NoteAdminDetailVO vo = BeanUtils.toBean(note, NoteAdminDetailVO.class);

        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(note.getCourseId(),false,false);
        if (courseInfo != null){
            vo.setCourseName(courseInfo.getName());
            List<Long> cateIds = List.of(
                    courseInfo.getFirstCateId(),
                    courseInfo.getSecondCateId(),
                    courseInfo.getThirdCateId());
            String categoryNames = categoryCache.getCategoryNames(cateIds);
            vo.setCategoryNames(categoryNames);
        }

        List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(List.of(note.getChapterId(),note.getSectionId()));
        if (cataInfos != null && cataInfos.size() == 2){
            for (CataSimpleInfoDTO cataInfo : cataInfos){
                if (cataInfo.getId().equals(note.getChapterId())){
                    vo.setChapterName(cataInfo.getName());
                }else if (cataInfo.getId().equals(note.getSectionId())){
                    vo.setSectionName(cataInfo.getName());
                }
            }
        }

        Set<Long> uIds = baseMapper.queryNoteGathers(id);
        Long authorId = note.getUserId();
        uIds.add(authorId);
        uIds.remove(0L);
        List<UserDTO> userDTOS = userClient.queryUserByIds(uIds);
        if (userDTOS != null && userDTOS.size() == uIds.size()){
            uIds.remove(authorId);

            userDTOS.stream().filter(u -> u.getId().equals(authorId)).findAny().ifPresent(u -> {
                vo.setAuthorName(u.getName());
                vo.setAuthorPhone(u.getCellPhone());
            });
            List<String> gatthers = userDTOS.stream()
                    .filter(u -> !u.getId().equals(authorId))
                    .map(UserDTO::getName)
                    .collect(Collectors.toList());
            vo.setGathers(gatthers);
        }
        return vo;
    }

    @Override
    public PageDTO<NoteAdminVO> queryNotesAdmin(NoteAdminPageQuery query) {
        Page<Note> notePage = new Page<>(query.getPageNo(),query.getPageSize());

        List<Long> courseidList = null;
        if (StringUtils.isNotBlank(query.getName())){
            courseidList = searchClient.queryCoursesIdByName(query.getName());

            if (CollUtils.isEmpty(courseidList)){
                return PageDTO.empty(notePage);
            }
        }

        if (StringUtils.isNotBlank(query.getSortBy())){
            notePage.addOrder(new OrderItem(query.getSortBy(),query.getIsAsc()));
        }else {
            notePage.addOrder(new OrderItem(Constant.DATA_FIELD_NAME_CREATE_TIME,false));
        }

        //搜索条件
        LocalDateTime beginTime = query.getBeginTime();
        LocalDateTime endTime = query.getEndTime();
        QueryWrapper<Note> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(query.getHidden() != null, Note::getHidden, query.getHidden())
                .in(!CollUtils.isEmpty(courseidList),Note::getCourseId,courseidList)
                .ge(beginTime != null, Note::getCreateTime, beginTime)
                .le(endTime != null, Note::getCreateTime, endTime);

        //查询
        Page<Note> pageDate = baseMapper.queryNotePage(notePage,wrapper);
        List<Note> records = pageDate.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(notePage);
        }

        List<NoteAdminVO> list = new ArrayList<>(records.size());
        Set<Long> courseIds = new HashSet<>();
        Set<Long> csIds = new HashSet<>();
        Set<Long> userIds = new HashSet<>();
        for (Note r : records){
            courseIds.add(r.getCourseId());
            if (r.getChapterId() != null) csIds.add(r.getChapterId());
            if (r.getSectionId() != null) csIds.add(r.getSectionId());
            userIds.add(r.getUserId());
        }

        List<CourseSimpleInfoDTO> courseInfos = courseClient.getSimpleInfoList(courseIds);
        Map<Long,String> courseMap = CollUtils.isEmpty(courseInfos) ?
                new HashMap<>() :
                courseInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, CourseSimpleInfoDTO::getName));

        List<CataSimpleInfoDTO> csInfos = catalogueClient.batchQueryCatalogue(csIds);
        Map<Long,String> csNmaeMap = CollUtils.isEmpty(csInfos) ?
                new HashMap<>() :
                csInfos.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));

        List<UserDTO> userInfos = userClient.queryUserByIds(userIds);
        Map<Long,String> userMap = CollUtils.isEmpty(userInfos) ?
                new HashMap<>() :
                userInfos.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));

        for (Note r : records){
            NoteAdminVO v = BeanUtils.toBean(r, NoteAdminVO.class);
            v.setCourseName(courseMap.get(r.getCourseId()));
            v.setChapterName(csNmaeMap.get(r.getChapterId()));
            v.setSectionName(csNmaeMap.get(r.getSectionId()));
            v.setAuthorName(userMap.get(r.getUserId()));
            list.add(v);
        }
        return new PageDTO<>(pageDate.getTotal(),pageDate.getPages(),list);
    }



    @Override
    public PageDTO<NoteVO> queryMyNotes(NotePageQuery query) {
        // 1.条件判断
        Long courseId = query.getCourseId();
        Long sectionId = query.getSectionId();
        if (courseId == null && sectionId == null) {
            throw new BadRequestException("课程或小节不能为空");
        }
        // 2.分页条件
        Page<Note> p = new Page<>(query.getPageNo(), query.getPageSize());
        // 3.获取用户
        Long userId = UserContext.getUser();
        // 4.搜索
        Page<Note> page = query.getOnlyMine() ?
                lambdaQuery()
                        .eq(Note::getUserId, userId)
                        .eq(Note::getHidden, false)
                        .eq(courseId != null, Note::getCourseId, courseId)
                        .eq(sectionId != null, Note::getSectionId, sectionId)
                        .orderByAsc(sectionId != null, Note::getNoteMoment)
                        .orderByDesc(sectionId == null, Note::getId)
                        .page(p)
                : baseMapper.queryNotePageBySectionId(p, userId, courseId, sectionId);
        // 5.数据处理
        return parseNotePages(page);
    }

    private PageDTO<NoteVO> parseNotePages(Page<Note> page) {
        List<Note> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }

        Set<Long> userIds = records.stream().map(Note::getUserId).collect(Collectors.toSet());
        List<UserDTO> stuInfos = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> sMap = CollUtils.isEmpty(stuInfos) ?
                new HashMap<>() :
                stuInfos.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));

        List<NoteVO> list = new ArrayList<>(records.size());
        for (Note r : records){
            NoteVO vo = BeanUtils.copyBean(r, NoteVO.class);
            UserDTO author = sMap.get(r.getAuthorId());
            if (author != null){
                vo.setAuthorId(author.getId());
                vo.setAuthorName(author.getName());
                vo.setAuthorIcon(author.getIcon());
            }
            vo.setIsGathered(BooleanUtils.isTrue(r.getIsGathered()));
            list.add(vo);
        }
        return new PageDTO<>(page.getTotal(), page.getPages(), list);
    }

    @Override
    public void removeMyId(Long id) {
        Long userId = UserContext.getUser();

        Note note = getById(id);

        AssertUtils.equals(note.getUserId(),userId,"只能删除自己的笔记");

        removeById(id);
    }

    @Override
    public void updateNote(NoteFormDTO noteFormDTO) {
        Long userId = UserContext.getUser();

        Note note = getById(noteFormDTO.getId());

        AssertUtils.isNotNull(note,"笔记不存在");

        AssertUtils.equals(note.getUserId(),userId,"只能修改自己的笔记");

        //封装数据
        Note n = new Note();
        n.setId(noteFormDTO.getId());
        if (noteFormDTO.getIsPrivate() != null){
            n.setIsPrivate(note.getIsPrivate() || note.getIsGathered());
        }
        n.setContent(noteFormDTO.getContent());
        updateById(n);
    }

    @Override
    public void removeGatherNote(Long id) {
        LambdaUpdateWrapper<Note> queryWrapper = Wrappers
                .lambdaUpdate(Note.class)
                .eq(Note::getUserId,UserContext.getUser())
                .eq(Note::getGatheredNoteId,id);

        baseMapper.delete(queryWrapper);
    }

    @Override
    @Transactional
    public void gatherNote(Long id) {
        Long userId = UserContext.getUser();

        Note note = getById(id);
        if (note == null || note.getIsPrivate() || note.getHidden()){
            throw  new BadRequestException("该笔记不存在");
        }

        note.setGatheredNoteId(note.getId());
        note.setIsGathered(true);
        note.setIsPrivate(true);
        note.setUserId(userId);
        note.setId(null);
        save(note);

        mqHelper.send(
                MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.NOTE_GATHERED,
                userId
        );
    }

    @Override
    @Transactional
    public void saveNote(NoteFormDTO noteFormDTO) {
        Long userId = UserContext.getUser();
        //1.数据转换
        Note note = BeanUtils.copyBean(noteFormDTO, Note.class);
        //2.获取用户
        note.setUserId(userId);
        note.setAuthorId(userId);
        //3.保存数据
        save(note);
        //4.发送mq消息增加积分
        mqHelper.send(
                MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.WRITE_NOTE,
                userId
        );
    }
}
